﻿using Genersoft.Platform.AppFramework.API;
using Genersoft.Platform.AppFramework.Core;
using Genersoft.Platform.AppFramework.Service;
using Genersoft.Platform.Core.DataAccess;
using Genersoft.Platform.Resource.CodeRuleManager;
using Microsoft.CSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace GenerSoft.JTGL.CommonFunc
{
    class CommonFunc
    {
        //product
        #region 配置文件读取: ~/JTGL/portal/{0}
        /// <summary>
        /// 配置文件读取
        /// </summary>
        /// <param name="configFile"> 配置文件名,位置：~/JTGL/portal/{0}</param>
        /// <param name="key">配置文件节点</param>
        /// <returns></returns>
        public static string GetCon(string configFile, string key)
        {
            string path = string.Format("~/JTGL/portal/{0}", configFile);
            System.IO.FileInfo FileInfo = new System.IO.FileInfo(HttpContext.Current.Server.MapPath(path));
            if (!FileInfo.Exists)
            {
                throw new Exception(string.Format("文件 : {0} 不存在", HttpContext.Current.Server.MapPath(path)));
            }
            XmlDocument Xml = new XmlDocument();
            Xml.Load(FileInfo.FullName);
            return Xml.SelectSingleNode("/pz/" + key).InnerXml.Trim();
        }
        #endregion

        #region 模拟登陆
        /// <summary>
        /// 模拟登陆并创建FIsession
        /// </summary>
        /// <param name="AppID">实例编号</param>
        /// <param name="UserCode">用户编号</param>
        /// <param name="PassWord">用户密码</param>
        /// <param name="vLoginDate">登陆日期</param>
        /// <param name="vDWBH">单位编号</param>
        /// <returns>进程ID</returns>
        public static string UserLogin(string AppID, string UserCode, string PassWord, string vLoginDate, string vDWBH)
        {
            string ProcessID = string.Empty;
            try
            {
                string date1 = Convert.ToDateTime(vLoginDate).ToString("yyyy-MM-dd");
                string date2 = Convert.ToDateTime(vLoginDate).ToString("yyyyMMdd");
                GSPLoginService login = new GSPLoginService();
                string tokenValue = login.Login(AppID, date1, UserCode, PassWord);
                string[] vsresult = tokenValue.Split('&');
                vsresult = vsresult[3].Split(':');
                ProcessID = vsresult[1];
                GSPState session = GSPContext.Current.Session;
                //FISessionManager mgr = new FISessionManager();
                //GSPState fiState = mgr.BuildFIState(session, date2, vDWBH);
                return ProcessID;
            }
            catch (Exception ex)
            {
                //PubFunc.WriteLog("模拟登陆出错:" + ex.Message);
                return "模拟登陆出错" + ex.Message;
            }
        }

        /// <summary>
        /// 模拟退出
        /// </summary>
        /// <param name="ProcessID">进程ID</param>
        /// <returns>返回结果</returns>
        public static string UserQuit(string ProcessID)
        {
            string vsSessionID;
            try
            {
                if (HttpContext.Current.Session["ProcessID"].ToString() != ProcessID)
                    return "-1;Session验证不通过";
                vsSessionID = GetState(ProcessID).ToDecodeString(false);
                IGSPToken iToken = new GSPGUIDToken(ProcessID);
                if (iToken == null)
                    return "-1;token is null;";
                GSPApplication gLogin = new GSPApplication();
                gLogin.UserLogout(iToken);
                HttpContext.Current.Session["ProcessID"] = "";
                HttpContext.Current.Session["SessionID"] = "";
            }
            catch (Exception e)
            {
                return "-1;" + e.Message;
            }
            return "1";
        }
        private static GSPState GetState(string ProcessID)
        {
            string vsState = HttpContext.Current.Session["SessionID"].ToString();
            GSPState stateTemp = new GSPState(new Hashtable());
            stateTemp.BuildState(vsState, true);
            GSPState.IgnoreCheck();
            GSPState.SetServerState(stateTemp);
            return stateTemp;
        }
        /// <summary>
        /// 日志记录模拟登陆状态
        /// </summary>
        /// <param name="txt"></param>
        public static void WriteLog(string txt)
        {
            string vsPath = @"C:\GS\";
            if (!Directory.Exists(vsPath))
                Directory.CreateDirectory(vsPath);
            vsPath = vsPath + "UserLogin_log.txt";
            StreamWriter sw = new StreamWriter(vsPath, true, Encoding.Default);
            DateTime currentTime = System.DateTime.Now;
            sw.WriteLine(currentTime + ":\r\n" + txt + "\r\n");
            sw.Close();
        }
        #endregion

        #region 构造服务端Session
        /// <summary>
        ///   appCode为数据库实例，在服务器 系统管理配置中查看，也可读取文件
        /// </summary>
        /// <param name="appCode">数据库实例</param>
        public static void CreateSession(string appCode)
        {
            Hashtable table = new Hashtable
            {
                { "AppInstanceID", appCode },
                { "BizDate", DateTime.Now.ToString() },
                { "LoginDate", DateTime.Now.ToString() },
                { "UserCode", "SYS" }
            };
            GSPState.IgnoreCheck();
            GSPState state = GSPState.CreateState(table, true);//重新生成ID
            GSPState.SetServerState(state);
        }
        /*① db获取调用：CreateSession(potal); IGSPDatabase db = GSPContext.Current.Database;*/
        /*② 模拟登陆*/
        /*③ 客户端调用服务端dll*/
        #endregion

        #region 生成报销单号
        /// <summary>
        /// 获取单据编号
        /// </summary>
        /// <param name="db">IGSPDatabase</param>
        /// <param name="strMXID">基础模型ID</param>
        /// <param name="strDJLX">单据类型</param>
        /// <param name="strGSsql">制单格式SQL</param>
        /// <returns>单据编号</returns>
        /// 申请 2fc63df3-0b0c-42c4-96c3-2bdee5aa0763  报销 44d8c4a6-8d69-40f7-a5c1-4e5506bcfbcc
        public static string GetDJBH(IGSPDatabase db, string strMXID, string strDJLX, string strGSsql, DataSet dsDJ)
        {
            string fileName = "SyncPurchaseOrder";
            string strObjectID = string.Empty;
            string strModelID = string.Empty;
            string strRuleID = string.Empty;
            string strColID = string.Empty;
            string strSQL = string.Format(@"WITH
                T1 AS (SELECT BIZMETADATACONTENTID--报账单据元数据内码
                FROM BIZUNITASSIGNMENT--运行时定制分配表
                WHERE BASEMETADATACONTENTID = '{0}'--网报基础模型内码
                {2}
                AND FIRSTLATITUDE = '{1}'),--报销类型内码
                T2 AS (SELECT SOURCEID--报账数据模型元数据内码
                FROM GSPMETADATACONSTRAINTS--依赖关系表
                WHERE TARGETID IN (SELECT BIZMETADATACONTENTID FROM T1)--报账单据元数据内码
                AND SOURCETYPE LIKE '%GspDataModel%'),--源类型为数据模型
                T3 AS (SELECT 
                INSTR(B.EXTEND1,'UseBizObjectID',1,1) LOC,--业务对象内码出现位置
                B.EXTEND1,--扩展信息
                A.MODELID,--模型内码
                A.COLUMNID,--列内码
                A.RULEID--规则内码
                FROM GSPCODERULEAPPLYTOS A
                JOIN GSPCODERULES B ON B.RULEID = A.RULEID
                WHERE A.MODELID IN (SELECT SOURCEID FROM T2)),
                T4 AS (SELECT
                INSTR(EXTEND1,'=',LOC,1) LOC1,
                INSTR(EXTEND1,';',LOC,1) LOC2,
                MODELID, COLUMNID, RULEID, EXTEND1
                FROM T3)
                SELECT
                NVL(SUBSTR(EXTEND1,LOC1+1,LOC2-LOC1-1),'FSBZYWBZ') APPLYTOOBJECTID,
                MODELID, COLUMNID, RULEID
                FROM T4"
                , strMXID, strDJLX, strGSsql);
            //PubFunc.Log(fileName, "查询SQL ：" + strSQL);
            DataSet dsCodeRules = db.ExecuteDataSet(strSQL);
            if ((DataSetValidator.IsDatasetValid(dsCodeRules)) == false)
            {
                return "没有查到数据，请检查报销类型与编码规则id对照表！";
            }
            strRuleID = Convert.ToString(dsCodeRules.Tables[0].Rows[0]["RULEID"]).Trim();
            strModelID = Convert.ToString(dsCodeRules.Tables[0].Rows[0]["MODELID"]).Trim();
            strObjectID = Convert.ToString(dsCodeRules.Tables[0].Rows[0]["APPLYTOOBJECTID"]);
            strColID = Convert.ToString(dsCodeRules.Tables[0].Rows[0]["COLUMNID"]);
            //PubFunc.Log(fileName, "--开始生成--");
            string strDJBH = NumberCodeGenerateManager.GetNumberCodeOnColumn(strObjectID, strModelID, strColID, strRuleID, string.Empty, dsDJ).FirstOrDefault();
            //PubFunc.Log(fileName, "--结束生成，\n --单据编号：" + strDJBH);
            return strDJBH;
        }
        #endregion

        //http
        #region HttpRequestMessage组织soap报文
        /// <summary>
        /// http请求报文-SOAP报文
        /// </summary>
        /// <param name="dicData">见参数示例-包含soap请求完整的xml节点 </param>
        /// <returns></returns>
        ///示例：{"msg":[{"soapenv":"http://schemas.xmlsoap.org/soap/envelope/"},{"web":"http://webservice.saas.fp.bwdz.com/"},{"checkMap":""},{"fpXml":{"body":{"fpdm":"3300181130","fphm":"14571268","nsrsbh":"91330300MA2863DA39","billingDate":"2018-05-30","paramsChoose":"3921.23","orderId":"123456"}}}]}
        public static string HttpRequestMessage(Dictionary<string, object> dicData)
        {
            try
            {
                JObject jo = JObject.Parse(JsonConvert.SerializeObject(dicData));
                string dicKey = string.Empty;//key
                string dicValue = string.Empty;//value
                foreach (var x in jo)
                {
                    dicKey = x.Key.ToString();
                    dicValue = x.Value.ToString();
                }
                string xmlns1Node = string.Empty;//命名空间节点和值
                string xmlns2Node = string.Empty;
                XNamespace xmlns1Value = string.Empty;
                XNamespace xmlns2Value = string.Empty;

                string child1Node = string.Empty;//子节点和值
                string child2Node = string.Empty;
                string child1Value = string.Empty;
                string child2Value = string.Empty;

                JArray isRight = JArray.Parse(jo[dicKey].ToString());
                if (isRight.Count != 4)
                {
                    throw new Exception("请求参数个数不准确，正确个数为4个，严格按照格式传入！");//代码自测
                    //return null;
                }
                foreach (var x in JObject.Parse(jo[dicKey][0].ToString()))
                {
                    xmlns1Node = x.Key;
                    xmlns1Value = x.Value.ToString().Replace("\"", string.Empty).Trim();
                    //Console.WriteLine(xmlns1Node);
                    //Console.WriteLine(xmlns1Value);
                }
                foreach (var x in JObject.Parse(jo[dicKey][1].ToString()))
                {
                    xmlns2Node = x.Key;
                    xmlns2Value = x.Value.ToString().Replace("\"", string.Empty).Trim();

                }
                foreach (var x in JObject.Parse(jo[dicKey][2].ToString()))
                {
                    child1Node = x.Key;
                    child1Value = x.Value.ToString().Replace("\"", string.Empty).Trim();//一般为空值

                }
                foreach (var x in JObject.Parse(jo[dicKey][3].ToString()))
                {
                    child2Node = x.Key;
                    child2Value = x.Value.ToString().Replace("\\", string.Empty).Trim();

                }
                //soapxml
                XDocument inDoc = new XDocument(new XDeclaration("1.0", "utf-16", null),
                    new XElement(xmlns1Value + "Envelope",
                        new XAttribute(XNamespace.Xmlns + xmlns1Node, xmlns1Value),
                        new XAttribute(XNamespace.Xmlns + xmlns2Node, xmlns2Value),
                        new XElement(xmlns1Value + "Header",
                            new XElement(xmlns1Value + "Body",
                                new XElement(xmlns2Value + child1Node,
                                    new XElement(child2Node, child2Value))))));
                return inDoc.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("组织SOAP报文异常>> " + ex.Message);
            }
        }
        #endregion

        #region httpRequest请求
        /// <summary>
        /// http请求
        /// </summary>
        /// <param name="strURL">请求地址</param>
        /// <param name="strMethod">请求方法：例如POST</param>
        /// <param name="dictHeaders">header头</param>
        /// <param name="strData">入参</param>
        /// <param name="strContentType">请求类型</param>
        /// <param name="bIsReturn">是否返回</param>
        /// <returns></returns>
        public static string HttpConnectToServer(string strURL, string strMethod, Dictionary<string, string> dictHeaders, string strContentType, string strData, bool bIsReturn)
        {
            try
            {
                string str = string.Empty;
                HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(strURL);
                httpWebRequest.Method = strMethod;
                httpWebRequest.ContentType = strContentType;
                foreach (string key in dictHeaders.Keys)
                {
                    httpWebRequest.Headers.Add(key, dictHeaders[key]);
                }
                //POST
                if ("POST".Equals(strMethod, StringComparison.CurrentCultureIgnoreCase))
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(strData);
                    httpWebRequest.ContentLength = (long)bytes.Length;
                    using (Stream requestStream = httpWebRequest.GetRequestStream())
                    {
                        requestStream.Write(bytes, 0, bytes.Length);
                        requestStream.Close();
                    }
                }
                //return?
                if (bIsReturn)
                {
                    Stream responseStream = httpWebRequest.GetResponse().GetResponseStream();
                    using (StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8))
                    {
                        str = streamReader.ReadToEnd();
                        streamReader.Close();
                    }
                    responseStream.Close();
                }
                else
                {
                    httpWebRequest.GetResponse();
                }
                return str;
            }
            catch (Exception ex)
            {
                throw new Exception(strMethod + "方式调用接口异常>> " + ex.Message);
            }
        }
        #endregion

        #region httpRequest-简易版
        /// <summary>
        /// 发送消息到服务器获取返回报文
        /// </summary>
        /// <param name="ServerUrl">wsdl地址</param>
        /// <param name="strData">json数据格式</param>
        /// <returns></returns>
        public static string HttpConnectToServerSimple(string ServerUrl, string strContentType, string strData)
        {
            byte[] dataArray = Encoding.UTF8.GetBytes(strData);
            //创建请求
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ServerUrl);
            request.Method = "POST";
            request.ContentLength = dataArray.Length;
            //request.ContentType = "application/json;charset=UTF-8";
            request.ContentType = strContentType;
            //创建输入流
            Stream dataStream = null;
            try
            {
                dataStream = request.GetRequestStream();
            }
            catch (Exception)
            {
                return null;//连接服务器失败
            }
            //发送请求
            dataStream.Write(dataArray, 0, dataArray.Length);
            dataStream.Close();
            //读取返回消息
            string res = string.Empty;
            try
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                res = reader.ReadToEnd();
                reader.Close();
            }
            catch (WebException ex)
            {
                HttpWebResponse response = (HttpWebResponse)ex.Response;

                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                res = sr.ReadToEnd();
                return null;//连接服务器失败
            }
            return res;
        }
        #endregion

        #region 调用WebService接口：http://...?wsdl，代码生成代理类，并调用返回结果==>可使用组织soap报文调用具体参考HttpRequest请求
        /// <summary>
        /// 实例化WebServices
        /// </summary>
        /// <param name="url">WebServices地址</param>
        /// <param name="methodname">调用的方法</param>
        /// <param name="args">把webservices里需要的参数按顺序放到这个object[]里</param>
        public object InvokeWebService(string url, string methodname, object[] args)
        {
            //这里的namespace是需引用的webservices的命名空间，我没有改过，也可以使用。也可以加一个参数从外面传进来。
            string @namespace = "client";

            try
            {
                //获取WSDL
                WebClient wc = new WebClient();
                Stream stream = wc.OpenRead(url);
                ServiceDescription sd = ServiceDescription.Read(stream);
                string classname = sd.Services[0].Name;
                ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
                sdi.AddServiceDescription(sd, "", "");
                CodeNamespace cn = new CodeNamespace(@namespace);

                //生成客户端代理类代码
                CodeCompileUnit ccu = new CodeCompileUnit();
                ccu.Namespaces.Add(cn);
                sdi.Import(cn, ccu);
                CSharpCodeProvider csc = new CSharpCodeProvider();
                //ICodeCompiler icc = csc.CreateCompiler();

                //设定编译参数
                CompilerParameters cplist = new CompilerParameters();
                cplist.GenerateExecutable = false;  //动态编译后的程序集不生成可执行文件
                cplist.GenerateInMemory = true;     //动态编译后的程序集只存在于内存中，不在硬盘的文件上
                cplist.ReferencedAssemblies.Add("System.dll");
                cplist.ReferencedAssemblies.Add("System.XML.dll");
                cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
                cplist.ReferencedAssemblies.Add("System.Data.dll");

                //编译代理类
                CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);
                if (true == cr.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }

                    throw new Exception(sb.ToString());
                }

                //生成代理实例，并调用方法
                System.Reflection.Assembly assembly = cr.CompiledAssembly;
                Type t = assembly.GetType(@namespace + "." + classname, true, true);
                object obj = Activator.CreateInstance(t);
                System.Reflection.MethodInfo mi = t.GetMethod(methodname);

                //注：method.Invoke(o, null)返回的是一个Object,如果你服务端返回的是DataSet,这里也是用(DataSet)method.Invoke(o, null)转一下就行了,method.Invoke(0,null)这里的null可以传调用方法需要的参数,string[]形式的
                return mi.Invoke(obj, args);
            }
            catch (Exception ex)
            {
                return "动态调用失败：" + ex.ToString();
            }
        }
        #endregion

        //api/rest
        #region HTTP请求-推待办？
        private string HttpPost(string url, string token, string json)
        {
            XmlDocument xml = new XmlDocument();
            xml.LoadXml("<burlap:call xmlns:burlap=\"http://www.w3.org/2001/XMLSchema-instance\"><method>rmtLogon</method></burlap:call>");
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            request.UserAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36";
            // turn our request string into a byte stream
            byte[] postBytes = Encoding.UTF8.GetBytes(json);
            request.Method = "POST";
            CookieContainer CookieArray = new CookieContainer();
            request.CookieContainer = CookieArray;

            request.Credentials = CredentialCache.DefaultCredentials;
            request.Timeout = 20000;
            request.ContentType = "application/json;charset=UTF-8";
            request.Accept = "application/json";
            request.ServicePoint.Expect100Continue = true;
            request.KeepAlive = true;
            request.ContentLength = postBytes.Length;
            if (token != "")
                request.Headers.Add("token", token);

            Stream requestStream = request.GetRequestStream();
            requestStream.Write(postBytes, 0, postBytes.Length);
            requestStream.Close();

            try
            {
                HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();//获得 服务端响应
                using (Stream responsestream = httpResponse.GetResponseStream())
                {
                    using (StreamReader sr = new StreamReader(responsestream, System.Text.Encoding.UTF8))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
            catch (Exception ex)
            {
                return "致远方系统接口异常，请联系管理员。异常信息：" + ex.Message;
            }
        }
        #endregion


        //Method
        #region 序列化xml
        /// <summary>
        /// 序列化object对象为XML字符串
        /// </summary>
        /// <param name="obj">实体类或List集合类</param>
        /// <returns></return>
        public static string XmlSerialize(object obj)
        {
            return XmlSerialize(obj, false, true);
        }
        /// <summary>
        /// 序列化object对象为XML字符串
        /// </summary>
        /// <param name="obj">实体类或List集合类</param>
        /// <param name="isOmitXmlDeclaration"><![CDATA[是否去除Xml声明<?xml version="1.0" encoding="utf-8"?>]]></param>
        /// <param name="isIndent">是否缩进显示</param>
        /// <returns></returns>
        public static string XmlSerialize(object obj, bool isOmitXmlDeclaration, bool isIndent)
        {
            try
            {
                string xmlString;
                XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();

                //去除xml声明
                //<?xml version="1.0" encoding="utf-8"?>
                xmlWriterSettings.OmitXmlDeclaration = isOmitXmlDeclaration;
                //不换行不缩进
                xmlWriterSettings.Indent = isIndent;
                //默认为UTF8编码
                xmlWriterSettings.Encoding = Encoding.UTF8;

                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
                    {
                        //去除默认命名空间xmlns:xsd和xmlns:xsi
                        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                        ns.Add("", "");

                        //序列化对象
                        XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
                        xmlSerializer.Serialize(xmlWriter, obj, ns);
                    }
                    xmlString = Encoding.UTF8.GetString(memoryStream.ToArray());
                }
                return xmlString.TrimStart('?');
            }
            catch (Exception)
            {
                return null;
            }
        }

        #endregion

        #region xml/流文件序列化和反序列化
        /// <summary>
        /// XMLHelper
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static string XmlSerialize<T>(T model) where T : class
        {
            //以下为标准序列化方式，可自写，也可调用
            string xml;
            using (var ms = new MemoryStream())
            {
                XmlSerializer xmlSer = new XmlSerializer(typeof(T));
                xmlSer.Serialize(ms, model);
                ms.Position = 0;
                StreamReader sr = new StreamReader(ms);
                xml = sr.ReadToEnd();
            }
            return xml;
        }

        /// <summary>
        /// 反序列化-xml文件
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="strXml">xml文件</param>
        /// <returns></returns>
        public static T XmlSerialize<T>(string strXml) where T : class
        {
            try
            {
                object obj;
                using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(strXml)))
                {
                    using (XmlReader xmlReader = XmlReader.Create(memoryStream))
                    {
                        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
                        obj = xmlSerializer.Deserialize(xmlReader);
                    }
                }
                return obj as T;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// 反序列化-流文件
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="stream">流文件</param>
        /// <returns></returns>
        public static T StreamDeserialize<T>(Stream stream) where T : class
        {
            try
            {
                object obj;
                XmlSerializer xmldes = new XmlSerializer(typeof(T));
                obj = xmldes.Deserialize(stream);

                return obj as T;
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion

        #region 格式化Json: String-->JSON
        /// <summary>
        /// 格式化JSON
        /// </summary>
        /// <param name="str">待格式化json字符串</param>
        /// <returns></returns>
        public static string ConvertStringToJson(string str)
        {
            try
            {
                //格式化json字符串
                JsonSerializer serializer = new JsonSerializer();
                TextReader tr = new StringReader(str);
                JsonTextReader jtr = new JsonTextReader(tr);
                object obj = serializer.Deserialize(jtr);
                if (obj != null)
                {
                    StringWriter textWriter = new StringWriter();
                    JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
                    {
                        Formatting = Newtonsoft.Json.Formatting.Indented,
                        Indentation = 4,
                        IndentChar = ' '
                    };
                    serializer.Serialize(jsonWriter, obj);
                    return textWriter.ToString();
                }
                else
                {
                    return str;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("格式化JSON出错>> " + ex.Message);
            }
        }
        #endregion

        #region 判断字符串是否为合法的JSON格式
        /// <summary>
        /// 判断一个字符串是不是合法的json字符串
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public bool IsJson(string json)
        {
            int errIndex;
            return IsJson(json, out errIndex);
        }

        private static bool IsJson(string json, out int errIndex)
        {
            errIndex = 0;
            if (IsJsonStart(ref json))
            {
                CharState cs = new CharState();
                char c;
                for (int i = 0; i < json.Length; i++)
                {
                    c = json[i];
                    if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。
                    {
                        string item = json.Substring(i);
                        int err;
                        int length = GetValueLength(item, true, out err);
                        cs.childrenStart = false;
                        if (err > 0)
                        {
                            errIndex = i + err;
                            return false;
                        }
                        i = i + length - 1;
                    }
                    if (cs.isError)
                    {
                        errIndex = i;
                        return false;
                    }
                }

                return !cs.arrayStart && !cs.jsonStart;
            }
            return false;
        }

        /// <summary>
        /// 是否是json开头的字符串
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        private static bool IsJsonStart(ref string json)
        {
            if (!string.IsNullOrEmpty(json))
            {
                json = json.Trim('\r', '\n', ' ');
                if (json.Length > 1)
                {
                    char s = json[0];
                    char e = json[json.Length - 1];
                    return (s == '{' && e == '}') || (s == '[' && e == ']');
                }
            }
            return false;
        }

        /// <summary>
        /// 获取值的长度（当Json值嵌套以"{"或"["开头时）
        /// </summary>
        private static int GetValueLength(string json, bool breakOnErr, out int errIndex)
        {
            errIndex = 0;
            int len = 0;
            if (!string.IsNullOrEmpty(json))
            {
                CharState cs = new CharState();
                char c;
                for (int i = 0; i < json.Length; i++)
                {
                    c = json[i];
                    if (!SetCharState(c, ref cs))//设置关键符号状态。
                    {
                        if (!cs.jsonStart && !cs.arrayStart)//json结束，又不是数组，则退出。
                        {
                            break;
                        }
                    }
                    else if (cs.childrenStart)//正常字符，值状态下。
                    {
                        int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值，返回一个长度。。。
                        cs.childrenStart = false;
                        cs.valueStart = 0;
                        //cs.state = 0;
                        i = i + length - 1;
                    }
                    if (breakOnErr && cs.isError)
                    {
                        errIndex = i;
                        return i;
                    }
                    if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。
                    {
                        len = i + 1;//长度比索引+1
                        break;
                    }
                }
            }
            return len;
        }
        /// <summary>
        /// 字符状态
        /// </summary>
        private class CharState
        {
            internal bool jsonStart = false;//以 "{"开始了...
            internal bool setDicValue = false;// 可以设置字典值了。
            internal bool escapeChar = false;//以"\"转义符号开始了
            /// <summary>
            /// 数组开始【仅第一开头才算】，值嵌套的以【childrenStart】来标识。
            /// </summary>
            internal bool arrayStart = false;//以"[" 符号开始了
            internal bool childrenStart = false;//子级嵌套开始了。
            /// <summary>
            /// 【0 初始状态，或 遇到“,”逗号】；【1 遇到“：”冒号】
            /// </summary>
            internal int state = 0;

            /// <summary>
            /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
            /// </summary>
            internal int keyStart = 0;
            /// <summary>
            /// 【-1 取值结束】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
            /// </summary>
            internal int valueStart = 0;
            internal bool isError = false;//是否语法错误。

            internal void CheckIsError(char c)//只当成一级处理（因为GetLength会递归到每一个子项处理）
            {
                if (keyStart > 1 || valueStart > 1)
                {
                    return;
                }
                //示例 ["aa",{"bbbb":123,"fff","ddd"}] 
                switch (c)
                {
                    case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
                        isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
                        break;
                    case '}':
                        isError = !jsonStart || (keyStart != 0 && state == 0);//重复结束错误 或者 提前结束{"aa"}。正常的有{}
                        break;
                    case '[':
                        isError = arrayStart && state == 0;//重复开始错误
                        break;
                    case ']':
                        isError = !arrayStart || jsonStart;//重复开始错误 或者 Json 未结束
                        break;
                    case '"':
                    case '\'':
                        isError = !(jsonStart || arrayStart); //json 或数组开始。
                        if (!isError)
                        {
                            //重复开始 [""",{"" "}]
                            isError = (state == 0 && keyStart == -1) || (state == 1 && valueStart == -1);
                        }
                        if (!isError && arrayStart && !jsonStart && c == '\'')//['aa',{}]
                        {
                            isError = true;
                        }
                        break;
                    case ':':
                        isError = !jsonStart || state == 1;//重复出现。
                        break;
                    case ',':
                        isError = !(jsonStart || arrayStart); //json 或数组开始。
                        if (!isError)
                        {
                            if (jsonStart)
                            {
                                isError = state == 0 || (state == 1 && valueStart > 1);//重复出现。
                            }
                            else if (arrayStart)//["aa,] [,]  [{},{}]
                            {
                                isError = keyStart == 0 && !setDicValue;
                            }
                        }
                        break;
                    case ' ':
                    case '\r':
                    case '\n'://[ "a",\r\n{} ]
                    case '\0':
                    case '\t':
                        break;
                    default: //值开头。。
                        isError = (!jsonStart && !arrayStart) || (state == 0 && keyStart == -1) || (valueStart == -1 && state == 1);//
                        break;
                }
                //if (isError)
                //{

                //}
            }
        }
        /// <summary>
        /// 设置字符状态(返回true则为关键词，返回false则当为普通字符处理）
        /// </summary>
        private static bool SetCharState(char c, ref CharState cs)
        {
            cs.CheckIsError(c);
            switch (c)
            {
                case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
                    #region 大括号
                    if (cs.keyStart <= 0 && cs.valueStart <= 0)
                    {
                        cs.keyStart = 0;
                        cs.valueStart = 0;
                        if (cs.jsonStart && cs.state == 1)
                        {
                            cs.childrenStart = true;
                        }
                        else
                        {
                            cs.state = 0;
                        }
                        cs.jsonStart = true;//开始。
                        return true;
                    }
                    #endregion
                    break;
                case '}':
                    #region 大括号结束
                    if (cs.keyStart <= 0 && cs.valueStart < 2 && cs.jsonStart)
                    {
                        cs.jsonStart = false;//正常结束。
                        cs.state = 0;
                        cs.keyStart = 0;
                        cs.valueStart = 0;
                        cs.setDicValue = true;
                        return true;
                    }
                    // cs.isError = !cs.jsonStart && cs.state == 0;
                    #endregion
                    break;
                case '[':
                    #region 中括号开始
                    if (!cs.jsonStart)
                    {
                        cs.arrayStart = true;
                        return true;
                    }
                    else if (cs.jsonStart && cs.state == 1)
                    {
                        cs.childrenStart = true;
                        return true;
                    }
                    #endregion
                    break;
                case ']':
                    #region 中括号结束
                    if (cs.arrayStart && !cs.jsonStart && cs.keyStart <= 2 && cs.valueStart <= 0)//[{},333]//这样结束。
                    {
                        cs.keyStart = 0;
                        cs.valueStart = 0;
                        cs.arrayStart = false;
                        return true;
                    }
                    #endregion
                    break;
                case '"':
                case '\'':
                    #region 引号
                    if (cs.jsonStart || cs.arrayStart)
                    {
                        if (cs.state == 0)//key阶段,有可能是数组["aa",{}]
                        {
                            if (cs.keyStart <= 0)
                            {
                                cs.keyStart = (c == '"' ? 3 : 2);
                                return true;
                            }
                            else if ((cs.keyStart == 2 && c == '\'') || (cs.keyStart == 3 && c == '"'))
                            {
                                if (!cs.escapeChar)
                                {
                                    cs.keyStart = -1;
                                    return true;
                                }
                                else
                                {
                                    cs.escapeChar = false;
                                }
                            }
                        }
                        else if (cs.state == 1 && cs.jsonStart)//值阶段必须是Json开始了。
                        {
                            if (cs.valueStart <= 0)
                            {
                                cs.valueStart = (c == '"' ? 3 : 2);
                                return true;
                            }
                            else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))
                            {
                                if (!cs.escapeChar)
                                {
                                    cs.valueStart = -1;
                                    return true;
                                }
                                else
                                {
                                    cs.escapeChar = false;
                                }
                            }

                        }
                    }
                    #endregion
                    break;
                case ':':
                    #region 冒号
                    if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0)
                    {
                        if (cs.keyStart == 1)
                        {
                            cs.keyStart = -1;
                        }
                        cs.state = 1;
                        return true;
                    }
                    // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1);
                    #endregion
                    break;
                case ',':
                    #region 逗号 //["aa",{aa:12,}]

                    if (cs.jsonStart)
                    {
                        if (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1)
                        {
                            cs.state = 0;
                            cs.keyStart = 0;
                            cs.valueStart = 0;
                            //if (cs.valueStart == 1)
                            //{
                            //    cs.valueStart = 0;
                            //}
                            cs.setDicValue = true;
                            return true;
                        }
                    }
                    else if (cs.arrayStart && cs.keyStart <= 2)
                    {
                        cs.keyStart = 0;
                        //if (cs.keyStart == 1)
                        //{
                        //    cs.keyStart = -1;
                        //}
                        return true;
                    }
                    #endregion
                    break;
                case ' ':
                case '\r':
                case '\n'://[ "a",\r\n{} ]
                case '\0':
                case '\t':
                    if (cs.keyStart <= 0 && cs.valueStart <= 0) //cs.jsonStart && 
                    {
                        return true;//跳过空格。
                    }
                    break;
                default: //值开头。。
                    if (c == '\\') //转义符号
                    {
                        if (cs.escapeChar)
                        {
                            cs.escapeChar = false;
                        }
                        else
                        {
                            cs.escapeChar = true;
                            return true;
                        }
                    }
                    else
                    {
                        cs.escapeChar = false;
                    }
                    if (cs.jsonStart || cs.arrayStart) // Json 或数组开始了。
                    {
                        if (cs.keyStart <= 0 && cs.state == 0)
                        {
                            cs.keyStart = 1;//无引号的
                        }
                        else if (cs.valueStart <= 0 && cs.state == 1 && cs.jsonStart)//只有Json开始才有值。
                        {
                            cs.valueStart = 1;//无引号的
                        }
                    }
                    break;
            }
            return false;
        }

        #endregion
 
    
    }
}
